import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.Scanner;
public class Client implements Runnable{
	private static boolean stop=true;
	private static int udp=0;
	private static String username="";
	private DatagramSocket udpclientSocket=null;
	
	public Client(){
		//Thread fuer Notificationlistener
		Thread udpClientThread = new Thread(this);
		udpClientThread.start();
		
	}
	
	
	public static void main(String[] args) throws Exception{
		//Parameter
		String host = "";
		String tcpport ="";
		String udpport = "";
		
		if (args.length==3){
			host = args[0];
			tcpport = args[1];
			udpport = args[2];
		}
		if (chkparam(host, tcpport, udpport)){
			//Instanz Notifylistener
			Client client = new Client();
			
			String sentence;
			String linestart=">";
			int tcp = Integer.parseInt(tcpport);
			udp = Integer.parseInt(udpport);
			
			//TCP Socket und I/OStreams
			Socket clientSocket = null;
			try{
				 clientSocket = new Socket(host,tcp);
			}
			catch(ConnectException ex){
				//Fehler wenn Server nicht verfuegbar
				System.out.println("Server '"+host+"' on port '"+tcp+"' is not available!");
				setStop(false);
				client.closeUDP();
				return;
			}
			ObjectOutputStream outToServer = new ObjectOutputStream(clientSocket.getOutputStream());
			ObjectInputStream inFromServer = new ObjectInputStream(clientSocket.getInputStream());
			
			//UDP Port an Server schicken
			outToServer.writeObject(new Messagepk((String.valueOf(udp))));
			
			Scanner inFromUser = new Scanner(System.in);
			ArrayList<String> inputLine;
			System.out.print(linestart);
			sentence = inFromUser.nextLine();
			
			
			while(isStop()){
				
				//Beende Client
				if((sentence.equals("!end"))){
					setStop(false);
					client.closeUDP();
					break;
				}
				else{
					Messagepk incomming = new Messagepk();
					try{
					//Sende Objekt an Server
					outToServer.writeObject(new Messagepk(sentence));
					//Warte auf Antwort von Server
					incomming = (Messagepk)(inFromServer.readObject());
					}
					catch (IOException e){
						System.out.println("Client disconnected from Server!");
						setStop(false);
						client.closeUDP();
						break;
					}
					//ArrayList der Message
					inputLine = incomming.getMessage();
					
					//ArrayList der Message auslesen
					for(int i =0;i<inputLine.size();i++){
						linestart = incomming.getUserLine();
						username=incomming.getUsername();
						System.out.println(inputLine.get(i));		
					}
					
					System.out.print(linestart);
					sentence = inFromUser.nextLine();
				}
				
			}
			//Beenden der offenen Vebindung und Stream
			try{outToServer.close();}
			catch(SocketException e){/*Verbindung zum Host verloren;*/}
			try{inFromServer.close();}
			catch(SocketException e){/*Verbindung zum Host verloren;*/}
			try{clientSocket.close();}
			catch(SocketException e){/*Verbindung zum Host verloren;*/}
			
			//Scanner schliessen
			inFromUser.close();
			
			
			
			if(isStop()){
				//Schleife zusaetzlich fur Notifylistener beenden
				setStop(false);
				//Schliesse UDPSocket
				client.closeUDP();
			}
			
			//Schleife zusaetzlich fur Notifylistener beenden
			
			
			
			
		}
		else{
			//Usage
			System.out.println("Usage: Java Client <Host> <TCPPort> <UDPPort>");
		}
		
	}
	public void closeUDP(){
			udpclientSocket.close();
	}
	@Override
	public void run() {
		
		//Oeffne neuen UDP Socket
		try {
			udpclientSocket= new DatagramSocket(udp);
		} catch (SocketException e) {
			System.out.println("UDP Port already in use");
			System.out.println("Please press enter to close the client");
			setStop(false);
			return;
		}
		
		while(isStop()){
			//erwartete Packeteigenschaften
			byte[] receiveData = new byte[1024];
			DatagramPacket receivePacket = new DatagramPacket(receiveData,receiveData.length);
		
			try {
				//Warte auf Packet
				udpclientSocket.receive(receivePacket);
				String receive = new String(receivePacket.getData());
				
				//Overhead des Packets wegschneiden
				char[] convert = new char[1024];
				convert = receive.toCharArray();
				receive="";
				for (int i=0;i<convert.length;i++){
					if(convert[i]>=32 && convert[i]<=126){
						receive+= String.valueOf(convert[i]);
					}
				}
				
				//Commands Uberpruefung
				SplittLine line = new SplittLine(receive);
				while(line.hasNext()){
					String notify = line.readNext();
					//Auktion wurde beendet
					if(notify.equals("!auction-ended")){
						String name = line.readNext();
						String hbit = line.readNext();
						String description=line.readNext();
						while (line.hasNext()){
							description +=" "+ line.readNext();
						}
						if(username.equals(name)){
							String message="The auction '"+description+"' has ended. You won with "+hbit+".";
							System.out.println(message);
							System.out.print(username+">");
						}
						else{
							System.out.println("The auction '"+description+"' has ended. "+name+" won with "+hbit+".");
							System.out.print(username+">");
						}
					}
					//Neue Betrag wurde auf Auktion geboten
					if(notify.equals("!new-bid")){
						String description = line.readNext();
						while (line.hasNext()){
							description +=" "+ line.readNext();
						}
						System.out.println("You have been overbid on '"+description+"'");
						System.out.print(username+">");
					}
					//Shutdownnotification vom Server
					if(notify.equals("!shutdown")){
						System.out.println("Server is not available anymore!");
						System.out.println("Please press enter to close the client");
					}
				}
				
				
			} catch (IOException e) {/*Verbindung zum Host verloren;*/}
		}
		
		
		
	}
	//Parametercheck
	public static boolean chkparam(String host, String tcpport, String udpport){
		if (host.equals("")||tcpport.equals("")||udpport.equals("")){
			return false;
		}
		try{
			int i = Integer.parseInt(tcpport);
			i = Integer.parseInt(udpport);
		}
		catch(NumberFormatException e){
			return false;
		}
		return true;
		
	}

	public static boolean isStop() {
		return stop;
	}


	public static void setStop(boolean stop) {
		Client.stop = stop;
	}

}